// Node-RED Function Node Code - 批量处理缓存的MQTT数据
// 定时执行，批量处理队列中的数据

// 初始化存储和缓存
if (!global.get('mqttDataStore')) {
    global.set('mqttDataStore', {});
}

// 缓存PROJECT_DATA以提高性能
let cachedProjectData = global.get('CACHED_PROJECT_DATA');
if (!cachedProjectData) {
    cachedProjectData = global.get('PROJECT_DATA') || [];
    global.set('CACHED_PROJECT_DATA', cachedProjectData);
}

// 构建projectId到tenantId的映射表
let projectToTenantMap = global.get('PROJECT_TENANT_MAP');
if (!projectToTenantMap) {
    projectToTenantMap = {};
    for (const project of cachedProjectData) {
        if (project.project_id && project.tenant_id) {
            projectToTenantMap[project.project_id.toString()] = project.tenant_id.toString();
        }
    }
    global.set('PROJECT_TENANT_MAP', projectToTenantMap);
}

// 快速查找tenantId
function findTenantId(projectId) {
    return projectToTenantMap[projectId.toString()] || null;
}

// 批量处理数据
function processBatch(dataItems) {
    const dataStore = global.get('mqttDataStore') || {};
    let processedCount = 0;
    
    for (const item of dataItems) {
        try {
            const { topic, payload } = item;
            const parts = topic.split('/');
            
            // 快速验证格式
            if (parts.length < 5 || parts[1] !== 'hbbtst' || parts[2] !== 'dra') {
                continue;
            }
            
            const projectId = parts[3];
            const propId = parts[4];
            const tenantId = findTenantId(projectId);
            
            if (!tenantId || !payload[0] || payload[0].val === undefined) {
                continue;
            }
            
            const value = payload[0].val;
            
            // 确保层级结构存在
            if (!dataStore[tenantId]) {
                dataStore[tenantId] = {};
            }
            if (!dataStore[tenantId][projectId]) {
                dataStore[tenantId][projectId] = {};
            }
            
            // 保存数据
            dataStore[tenantId][projectId][propId] = {
                value: value,
                timestamp: new Date().toISOString(),
                lastUpdate: Date.now()
            };
            
            processedCount++;
            
        } catch (error) {
            // 静默忽略单个项目的错误，继续处理其他数据
            continue;
        }
    }
    
    // 批量保存
    global.set('mqttDataStore', dataStore);
    return processedCount;
}

// 清理过期数据函数 - 移除30分钟前的数据
function cleanExpiredData() {
    const queue = global.get('mqttDataQueue') || [];
    const now = Date.now();
    const thirtyMinutesAgo = now - (30 * 60 * 1000); // 30分钟 = 30 * 60 * 1000毫秒
    
    // 过滤掉过期数据，保留30分钟内的数据
    const validData = queue.filter(item => item.timestamp > thirtyMinutesAgo);
    const expiredCount = queue.length - validData.length;
    
    if (expiredCount > 0) {
        global.set('mqttDataQueue', validData);
    }
    
    return { cleanedCount: expiredCount, remainingCount: validData.length };
}

try {
    // 首先清理过期数据
    const cleanResult = cleanExpiredData();
    
    // 从队列中批量获取数据
    const queue = global.get('mqttDataQueue') || [];
    if (queue.length === 0) {
        return { 
            payload: { 
                message: 'No data to process', 
                queueSize: 0,
                expiredDataCleaned: cleanResult.cleanedCount
            } 
        };
    }
    
    // 动态批量处理 - 根据队列长度调整批次大小
    let batchSize = 100;
    if (queue.length > 2000) {
        batchSize = 500; // 积压严重时加大批次
    } else if (queue.length > 1000) {
        batchSize = 200; // 积压较多时适当增加
    }
    
    const actualBatchSize = Math.min(batchSize, queue.length);
    const batch = queue.splice(0, actualBatchSize);
    global.set('mqttDataQueue', queue);
    
    // 处理数据
    const processedCount = processBatch(batch);
    
    return {
        payload: {
            processed: processedCount,
            batchSize: actualBatchSize,
            remainingQueue: queue.length,
            expiredDataCleaned: cleanResult.cleanedCount,
            timestamp: new Date().toISOString()
        }
    };
    
} catch (error) {
    node.error('Processor error: ' + error.message);
    return null;
}